home *** CD-ROM | disk | FTP | other *** search
- /*==========================================================================
- *
- * !BEST002.C Tuesday, April 12, 1994
- *
- * source file 2D and 3D matrix/vector library
- * supplementary source file 2 for The BESTLibrary
- *
- * Authored by George Vanous with reference to the 2D and 3D vector library
- * by Andrew Glassner from "Graphics Gems", Academic Press, 1990
- *
- *==========================================================================*/
-
-
- /* ------------------------------------------------------------------------ */
- /* ---------------------------- INCLUDE FILES --------------------------- */
-
- #include <math.h>
- #include "!best002.h" /* include !BEST002.H in compilation */
-
- /*==========================================================================
- * 3X3 MATRICES
- *--------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- * C = A + B
- * RETURNS: C
- */
- matrix3 *m3_add(matrix3 *A, matrix3 *B, matrix3 *C)
- {
- word i;
- register word j;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++)
- C->element[i][j] = A->element[i][j] + B->element[i][j];
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: copy of A
- */
- matrix3 *m3_copy(matrix3 *A)
- {
- matrix3 *B = NEWTYPE(matrix3);
- register word i, j;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++)
- B->element[i][j] = A->element[i][j];
- }
- return( B );
- }
-
- /*----------------------------------------------------------------------------
- * C = A * B
- * RETURNS: C
- */
- matrix3 *m3_mul(matrix3 *A, matrix3 *B, matrix3 *C)
- {
- word i;
- register word j, k;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++) {
- C->element[i][j] = 0;
- for (k = 0; k < 3; k++)
- C->element[i][j] += A->element[i][k] * B->element[k][j];
- }
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: new 3x3 matrix initialized to a[3][3]
- */
- matrix3 *m3_new(double *a[3][3])
- {
- matrix3 *A = NEWTYPE(matrix3);
- register word i, j;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++)
- A->element[i][j] = *a[i][j];
- }
- return( A );
- }
- /*----------------------------------------------------------------------------
- * C = A - B
- * RETURNS: C
- */
- matrix3 *m3_sub(matrix3 *A, matrix3 *B, matrix3 *C)
- {
- word i;
- register word j;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++)
- C->element[i][j] = A->element[i][j] - B->element[i][j];
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * B = transpose(A)
- * RETURNS: B
- */
- matrix3 *m3_transpose(matrix3 *A, matrix3 *B)
- {
- register word i, j;
-
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 3; j++)
- B->element[i][j] = A->element[j][i];
- }
- return( B );
- }
-
- /*==========================================================================
- * 4x4 MATRICES
- *--------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- * C = A + B
- * RETURNS: C
- */
- matrix4 *m4_add(matrix4 *A, matrix4 *B, matrix4 *C)
- {
- word i;
- register word j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- C->element[i][j] = A->element[i][j] + B->element[i][j];
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: copy of A
- */
- matrix4 *m4_copy(matrix4 *A)
- {
- matrix4 *B = NEWTYPE(matrix4);
- register word i, j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- B->element[i][j] = A->element[i][j];
- }
- return( B );
- }
-
- /*----------------------------------------------------------------------------
- * C = A * B
- * RETURNS: C
- */
- matrix4 *m4_mul(matrix4 *A, matrix4 *B, matrix4 *C)
- {
- word i;
- register word j, k;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- c->element[i][j] = 0;
- for (k = 0; k < 4; k++)
- C->element[i][j] += A->element[i][k] * B->element[k][j];
- }
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: new 4x4 matrix initialized to a[4][4]
- */
- matrix4 *m4_new(double *a[4][4])
- {
- matrix4 *A = NEWTYPE(matrix4);
- register word i, j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- A->element[i][j] = *a[i][j];
- }
- return( A );
- }
-
- /*----------------------------------------------------------------------------
- * C = A - B
- * RETURNS: C
- */
- matrix4 *m4_sub(matrix4 *A, matrix4 *B, matrix4 *C)
- {
- word i;
- register word j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- C->element[i][j] = A->element[i][j] - B->element[i][j];
- }
- return( C );
- }
-
- /*----------------------------------------------------------------------------
- * B = transpose(A)
- * RETURNS: B
- */
- matrix4 *m4_transpose(matrix4 *A, matrix4 *B)
- {
- register word i, j;
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++)
- B->element[i][j] = A->element[j][i];
- }
- return( B );
- }
-
- /*==========================================================================
- * 2D VECTORS
- *--------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- * w = u + v
- * RETURNS: w
- */
- vector2 *v2_add(vector2 *u, vector2 *v, vector2 *w)
- {
- w->x = u->x + v->x, w->y = u->y + v->y;
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = c1(u) + c2(v)
- * RETURNS: w
- */
- vector2 *v2_combine(vector2 *u, double c1,
- vector2 *v, double c2, vector2 *w)
- {
- w->x = (c1 * u->x) + (c2 * v->x);
- w->y = (c1 * u->y) + (c2 * v->y);
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: copy of u
- */
- vector2 *v2_copy(vector2 *v)
- {
- vector2 *w = NEWTYPE(vector2);
-
- w->x = v->x, w->y = v->y;
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = u dot v
- * RETURNS: w
- */
- double v2_dot(vector2 *u, vector2 *v)
- {
- return( (u->x * v->x) + (u->y * v->y) );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: magnitude of v
- */
- double v2_len(vector2 *v)
- {
- return( sqrt(V2SquaredLength(v)) );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: magnitude of v squared
- */
- double v2_len_sqr(vector2 *v)
- {
- return( (v->x * v->x) + (v->y * v->y) );
- }
-
- /*----------------------------------------------------------------------------
- * w = linear interpolation between lo and hi by amount alpha
- * RETURNS: w
- */
- vector2 *v2_lerp(vector2 *lo, vector2 *hi, double alpha, vector2 *w)
- {
- w->x = LERP(alpha, lo->x, hi->x);
- w->y = LERP(alpha, lo->y, hi->y);
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = u * v (multiplication component-wise)
- * RETURNS: w
- */
- vector2 *v2_mul(vector2 *u, vector2 *v, vector2 *w)
- {
- w->x = u->x * v->x;
- w->y = u->y * v->y;
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: transformed point p * projection matrix m
- */
- point2 *v2_mul_by_proj(point2 *p, matrix3 *A)
- {
- double w;
- point2 q;
-
- q.x = (p->x * A->element[0][0]) +
- (p->y * A->element[1][0]) + A->element[2][0];
- q.y = (p->x * A->element[0][1]) +
- (p->y * A->element[1][1]) + A->element[2][1];
- w = (p->x * A->element[0][2]) +
- (p->y * A->element[1][2]) + A->element[2][2];
- if (w != 0.0)
- q.x /= w, q.y /= w;
- *p = q;
- return( q );
- }
-
- /*----------------------------------------------------------------------------
- * v is negated
- * RETURNS: v
- */
- vector2 *v2_neg(vector2 *v)
- {
- v->x = -v->x, v->y = -v->y;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: new 2D vector initialized to (x,y)
- */
- vector2 *v2_new(double x, double y)
- {
- vector2 *u = NEWTYPE(vector2);
-
- u->x = x, u->y = y;
- return( u );
- }
-
- /*----------------------------------------------------------------------------
- * v is normalized (becomes unit length)
- * RETURNS: v
- */
- vector2 *v2_norm(vector2 *v)
- {
- double len = V2Length(v);
-
- if (len != 0.0)
- v->x /= len, v->y /= len;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * u = some orthogonal vector to v
- * RETURNS: u
- */
- vector2 *v2_ortho(vector2 *u, vector2 *v)
- {
- v->x = -u->y;
- v->y = u->x;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * v is scaled to length newlen
- * RETURNS: v
- */
- vector2 *v2_scale(vector2 *v, double newlen)
- {
- double len = V2Length(v);
-
- if (len != 0.0)
- v->x *= newlen/len, v->y *= newlen/len;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: length of line segment pq
- */
- double v2_seg_len(point2 *p, point2 *q)
- {
- double dx = p->x - q->x;
- double dy = p->y - q->y;
-
- return( sqrt(dx*dx + dy*dy) );
- }
-
- /*----------------------------------------------------------------------------
- * w = u - v
- * RETURNS: w
- */
- vector2 *v2_sub(vector2 *u, vector2 *v, vector2 *w)
- {
- w->x = u->x - v->x, w->y = u->y - v->y;
- return( w );
- }
-
-
- /*==========================================================================
- * 3D VECTORS
- *--------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- * w = u + v
- * RETURNS: w
- */
- vector3 *v3_add(vector3 *u, vector3 *v, vector3 *w)
- {
- w->x = u->x + v->x, w->y = u->y + v->y, w->z = u->z + v->z;
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = c1(u) + c2(v)
- * RETURNS: w
- */
- vector3 *v3_combine(vector3 *u, double c1,
- vector3 *v, double c2, vector3 *w)
- {
- w->x = (c1 * u->x) + (c2 * v->x);
- w->y = (c1 * u->y) + (c2 * v->y);
- w->z = (c1 * u->z) + (c2 * v->z);
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: copy of u
- */
- vector3 *v3_copy(vector3 *v)
- {
- vector3 *w = NEWTYPE(vector3);
-
- w->x = v->x, w->y = v->y, w->z = v->z;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * w = u cross v
- * RETURNS: w
- */
- vector3 *v3_cross(vector3 *u, vector3 *v, vector3 *w)
- {
- w->x = (u->y * v->z) - (u->z * v->y);
- w->y = (u->z * v->x) - (u->x * v->z);
- w->z = (u->x * v->y) - (u->y * v->x);
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = u dot v
- * RETURNS: w
- */
- double v3_dot(vector3 *u, vector3 *v)
- {
- return( (u->x * v->x) + (u->y * v->y) + (u->z * v->z) );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: magnitude of v
- */
- double v3_len(vector3 *v)
- {
- return( sqrt(v3_len_sqr(v)) );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: magnitude of v squared
- */
- double v3_len_sqr(vector3 *v)
- {
- return( (v->x * v->x) + (v->y * v->y) + (v->z * v->z) );
- }
-
- /*----------------------------------------------------------------------------
- * w = linear interpolation between lo and hi by amount alpha
- * RETURNS: w
- */
- vector3 *v3_lerp(vector3 *lo, vector3 *hi, double alpha, vector3 *w)
- {
- w->x = LERP(alpha, lo->x, hi->x);
- w->y = LERP(alpha, lo->y, hi->y);
- w->z = LERP(alpha, lo->z, hi->z);
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * w = u * v (multiplication component-wise)
- * RETURNS: w
- */
- vector3 *v3_mul(vector3 *u, vector3 *v, vector3 *w)
- {
- w->x = u->x * v->x;
- w->y = u->y * v->y;
- w->z = u->z * v->z;
- return( w );
- }
-
- /*----------------------------------------------------------------------------
- * q = p * A
- * RETURNS: transformed point q
- */
- point3 *v3_mul_by_matrix(point3 *p, matrix3 *A, point3 *q)
- {
- q->x = (p->x * A->element[0][0])
- + (p->y * A->element[1][0]) + (p->z * A->element[2][0]);
- q->y = (p->x * A->element[0][1])
- + (p->y * A->element[1][1]) + (p->z * A->element[2][1]);
- q->z = (p->x * A->element[0][2])
- + (p->y * A->element[1][2]) + (p->z * A->element[2][2]);
- return( q );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: transformed point p * projection matrix A
- */
- point3 *v3_mul_by_proj(point3 *p, matrix4 *A)
- {
- double w;
- point3 q;
-
- q.x = (p->x * A->element[0][0]) + (p->y * A->element[1][0])
- + (p->z * A->element[2][0]) + A->element[3][0];
- q.y = (p->x * A->element[0][1]) + (p->y * A->element[1][1])
- + (p->z * A->element[2][1]) + A->element[3][1];
- q.z = (p->x * A->element[0][2]) + (p->y * A->element[1][2])
- + (p->z * A->element[2][2]) + A->element[3][2];
- w = (p->x * A->element[0][3]) + (p->y * A->element[1][3])
- + (p->z * A->element[2][3]) + A->element[3][3];
- if (w != 0.0)
- q.x /= w, q.y /= w, q.z /= w;
- *p = q;
- return( q );
- }
-
- /*----------------------------------------------------------------------------
- * v is negated
- * RETURNS: v
- */
- vector3 *v3_neg(vector3 *v)
- {
- v->x = -v->x, v->y = -v->y, v->z = -v->z;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: new 3D vector initialized to (x,y,z)
- */
- vector3 *v3_new(double x, double y, double z)
- {
- vector3 *v = NEWTYPE(vector3);
-
- v->x = x, v->y = y, v->z = z;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * v is normalized (becomes unit length)
- * RETURNS: v
- */
- vector3 *v3_norm(vector3 *v)
- {
- double len = v3_len(v);
-
- if (len != 0.0)
- v->x /= len, v->y /= len, v->z /= len;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * v is scaled to length newlen
- * RETURNS: v
- */
- vector3 *v3_scale(vector3 *v, double newlen)
- {
- double len = v3Length(v);
-
- if (len != 0.0)
- v->x *= newlen/len, v->y *= newlen/len, v->z *= newlen/len;
- return( v );
- }
-
- /*----------------------------------------------------------------------------
- * RETURNS: length of line segment pq
- */
- double v3_seg_len(point3 *p, point3 *q)
- {
- double dx = p->x - q->x;
- double dy = p->y - q->y;
- double dz = p->z - q->z;
-
- return( sqrt(dx*dx + dy*dy + dz*dz) );
- }
-
- /*----------------------------------------------------------------------------
- * w = u - v
- * RETURNS: w
- */
- vector3 *v3_sub(vector3 *u, vector3 *v, vector3 *w)
- {
- w->x = u->x - v->x; w->y = u->y - v->y; w->z = u->z - v->z;
- return( w );
- }
-
- /*==========================================================================
- * USEFUL ROUTINES
- *--------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------
- * binary greatest common divisor by Silver and Terzian. See Knuth
- * both inputs must be >= 0
- */
- int gcd(int u, int v)
- {
- int k, t, f;
-
- if (u < 0 || v < 0)
- return( 1 ); /* error if u < 0 or v < 0 */
- k = 0, f = 1;
- while ((u%2 == 0) && (v%2 == 0)) {
- k++;
- u >>= 1;
- v >>= 1;
- f *= 2;
- }
- if (u & 1) {
- t = -v;
- goto B4;
- }
- else
- t = u;
- B3:
- if (t > 0)
- t >>= 1;
- else
- t = -((-t) >> 1);
- B4:
- if (t%2 == 0)
- goto B3;
-
- if (t > 0)
- u = t;
- else
- v = -t;
- if ((t = u-v) != 0)
- goto B3;
- return( u*f );
- }
-
- /*----------------------------------------------------------------------------
- * return roots of a*x^2 + b*x + c
- * stable algebra derived from Numerical Recipes by Press et al
- */
- int quadraticRoots(double a, double b, double c, double *roots)
- {
- double d, q;
- int count = 0;
-
- d = b*b - 4*a*c;
- if (d < 0.0) {
- *roots = *(roots+1) = 0.0;
- return( 0 );
- }
- q = -0.5 * (b + SGN(b)*sqrt(d));
- if (a != 0.0) {
- *roots++ = q/a;
- count++;
- }
- if (q != 0.0) {
- *roots++ = c/q;
- count++;
- }
- return( count );
- }
-
-
- /*----------------------------------------------------------------------------
- * generic 1d regula-falsi step. f is function to evaluate
- * interval known to contain root is given in left, right
- * returns new estimate
- */
- double RegulaFalsi(double (*f)(), double left, double right)
- {
- double d = (*f)(right) - (*f)(left);
-
- if (d != 0.0)
- return( right - (*f)(right) * (right - left) / d);
- return( (left+right) / 2.0 );
- }
-
- /*----------------------------------------------------------------------------
- * generic 1d Newton-Raphson step. f is function, df is derivative
- * x is current best guess for root location. Returns new estimate
- */
- double NewtonRaphson(double (*f)(), double (*df)(), double x)
- {
- double d = (*df)(x);
-
- if (d != 0.0)
- return( x - ((*f)(x) / d) );
- return( x - 1.0 );
- }
-
-
- /*----------------------------------------------------------------------------
- * hybrid 1d Newton-Raphson/Regula Falsi root finder
- * input function f and its derivative df, an interval
- * left, right known to contain the root, and an error tolerance
- * Based on Blinn
- */
- double findroot(double left, double right,
- double tolerance, double (*f)(), double (*df)())
- {
- double newx = left;
-
- while (ABS((*f)(newx)) > tolerance) {
- newx = NewtonRaphson(f, df, newx);
- if (newx < left || newx > right)
- newx = RegulaFalsi(f, left, right);
- if ((*f)(newx) * (*f)(left) <= 0.0)
- right = newx;
- else
- left = newx;
- }
- return( newx );
- }
-
- /*============================== END-OF-FILE =============================*/
-